﻿using System;
using CalcSharp.Core;
using CalcSharp.Core.Containers;

namespace plug_mtrximage.HelperClasses
{
    public enum SimpleEfect
    {
        Invert,
        Grayscale,
        Sepia,
        RGB2BGR
    }

    public enum ParamEfect
    {
        Contrast,
        Brightness,
    }

    public partial class Efects
    {
        public static AMatrix SimpleColorEfect(AMatrix m, SimpleEfect efect, MtrxStorageType t)
        {
            AMatrix ret;
            int i, j;
            Int24 icol = new Int24();
            Int96 rcol = new Int96();

            switch (t)
            {
                case MtrxStorageType.tint24:
                    ret = new Int24Matrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tdouble:
                    ret = new DoubleMatrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tfloat:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
                default:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
            }

            switch (efect)
            {
                case SimpleEfect.Grayscale:
                    #region Grayscale
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            rcol.R = (icol.R + icol.G + icol.B) / 3;
                            rcol.G = rcol.R;
                            rcol.B = rcol.R;
                            ret[i, j] = rcol.ToInt32();
                        }
                    }
                    break;
                    #endregion
                case SimpleEfect.Invert:
                    #region Invert
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            rcol.R = 255 - icol.R;
                            rcol.G = 255 - icol.G;
                            rcol.B = 255 - icol.B;
                            ret[i, j] = rcol.ToInt32();
                        }
                    }
                    break;
                    #endregion
                case SimpleEfect.RGB2BGR:
                    #region RGB2BGR
                    Int24 inv = new Int24();
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            inv.R = icol.B;
                            inv.G = icol.G;
                            inv.B = icol.R;
                            ret[i, j] = inv.ToInt32();
                        }
                    }
                    break;
                    #endregion
                case SimpleEfect.Sepia:
                    #region Sepia
                    double tmp;
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            tmp = (double)(icol.R * 0.393) + (icol.G * 0.769) + (icol.B * 0.189);
                            rcol.R = (int)tmp;
                            tmp = (double)(icol.R * 0.349) + (icol.G * 0.686) + (icol.B * 0.168);
                            rcol.G = (int)tmp;
                            tmp = (double)(icol.R * 0.272) + (icol.G * 0.534) + (icol.B * 0.131);
                            rcol.B = (int)tmp;
                            ret[i, j] = rcol.ToInt32();
                        }
                    }
                    break;
                    #endregion
            }
            return ret;
        }

        public static AMatrix ContrastBrightness(AMatrix m, int Value, ParamEfect pr, MtrxStorageType t)
        {
            AMatrix ret;
            int i, j;
            Int24 icol = new Int24();
            Int96 rcol = new Int96();
            switch (t)
            {
                case MtrxStorageType.tint24:
                    ret = new Int24Matrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tdouble:
                    ret = new DoubleMatrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tfloat:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
                default:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
            }

            switch (pr)
            {
                case ParamEfect.Contrast:
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            rcol.R = (((icol.R - 128) * Value) / 100) + 128;
                            rcol.G = (((icol.G - 128) * Value) / 100) + 128;
                            rcol.B = (((icol.B - 128) * Value) / 100) + 128;
                            ret[i, j] = rcol.ToInt32();
                        }
                    }
                    break;
                case ParamEfect.Brightness:
                    for (i = 0; i < ret.Rows; i++)
                    {
                        for (j = 0; j < ret.Columns; j++)
                        {
                            icol.FromInt32((int)m[i, j]);
                            rcol.R = icol.R + Value;
                            rcol.G = icol.G + Value;
                            rcol.B = icol.B + Value;
                            ret[i, j] = rcol.ToInt32();
                        }
                    }
                    break;
            }
            return ret;
        }

        public static AMatrix ColorMix(AMatrix m, int Rp, int Gp, int Bp, MtrxStorageType t)
        {
            AMatrix ret;
            int i, j;
            Int24 icol = new Int24();
            Int96 rcol = new Int96();
            switch (t)
            {
                case MtrxStorageType.tint24:
                    ret = new Int24Matrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tdouble:
                    ret = new DoubleMatrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tfloat:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
                default:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
            }

            for (i = 0; i < ret.Rows; i++)
            {
                for (j = 0; j < ret.Columns; j++)
                {
                    icol.FromInt32((int)m[i, j]);
                    rcol.R = Convert.ToInt32((double)icol.R * (double)Rp / 100);
                    rcol.G = Convert.ToInt32((double)icol.G * (double)Gp / 100);
                    rcol.B = Convert.ToInt32((double)icol.R * (double)Bp / 100);
                    ret[i, j] = rcol.ToInt32();
                }
            }

            return ret;
        }

        public static AMatrix Gamma(AMatrix m, double Gamma, MtrxStorageType t)
        {
            AMatrix ret;
            int i, j;
            Int24 icol = new Int24();
            Int96 rcol = new Int96();
            if (Gamma < 0.2 || Gamma > 5) throw new CSException("Gamma mus be betwen 0,2 and 5");

            switch (t)
            {
                case MtrxStorageType.tint24:
                    ret = new Int24Matrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tdouble:
                    ret = new DoubleMatrix(m.Rows, m.Columns);
                    break;
                case MtrxStorageType.tfloat:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
                default:
                    ret = new FloatMatrix(m.Rows, m.Columns);
                    break;
            }

            byte[] redGamma = new byte[256];
            byte[] greenGamma = new byte[256];
            byte[] blueGamma = new byte[256];
            for (i = 0; i < 256; ++i)
            {
                redGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / Gamma)) + 0.5));
                greenGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / Gamma)) + 0.5));
                blueGamma[i] = (byte)Math.Min(255, (int)((255.0 * Math.Pow(i / 255.0, 1.0 / Gamma)) + 0.5));
            }
            for (i = 0; i < ret.Rows; i++)
            {
                for (j = 0; j < ret.Columns; j++)
                {
                    icol.FromInt32((int)m[i, j]);
                    rcol.R = redGamma[icol.R];
                    rcol.B = blueGamma[icol.B];
                    rcol.G = greenGamma[icol.G];
                    ret[i, j] = rcol.ToInt32();
                }
            }
            return ret;
        }
    }
}
